//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#ifndef __ELASTOS_KMALLOC_H__
#define __ELASTOS_KMALLOC_H__

#include <elatypes.h>
#include <ddk.h>


#if defined(KERNEL_MEMORY_DETECT)

EXTERN Void KMemInsertIntoHash(const PVoid pv, const UInt32 uSizeOrOrder,
                                Boolean bPhysPage = FALSE);
EXTERN Boolean KMemDetachFromHash(PVoid pv, Boolean bPhysPage = FALSE);

#ifndef KMEM_INSERT_INTO_HASH
#define KMEM_INSERT_INTO_HASH \
    do { \
        KMemInsertIntoHash(pv, (UInt32)size); \
    } while(0);

#endif //KMEM_INSERT_INTO_HASH

#ifndef KMEM_DETACH_FROM_HASH
#define KMEM_DETACH_FROM_HASH \
    do { \
        if (!KMemDetachFromHash(pv)) { \
            kprintf("\nERROR: Try to free an invalid block of kernel memory!\n"); \
            DebugBreak(); \
        } \
    } while(0);
#endif //KMEM_DETACH_FROM_HASH

#else

#define KMEM_INSERT_INTO_HASH
#define KMEM_DETACH_FROM_HASH

#endif //KERNEL_MEMORY_DETECT

EXTERN_C uint_t * CDECL kmalloc(uint_t);
EXTERN_C void CDECL kfree(uint_t *);

#define SIZE_TO_INDEX(s)    \
    ((s) <= (PAGE_SIZE >> 7) ? 0: \
    ((s) <= (PAGE_SIZE >> 6) ? 1: \
    ((s) <= (PAGE_SIZE >> 5) ? 2: \
    ((s) <= (PAGE_SIZE >> 4) ? 3: \
    ((s) <= (PAGE_SIZE >> 3) ? 4: \
    ((s) <= (PAGE_SIZE >> 2) ? 5: \
    ((s) <= (PAGE_SIZE >> 1) ? 6: \
    ((s) <= (PAGE_SIZE) ? 7:(UInt32)-1))))))))

#define INDEX_TO_SIZE(s)    \
    ((s) == 0 ? 32: \
    ((s) == 1 ? 64: \
    ((s) == 2 ? 128: \
    ((s) == 3 ? 256: \
    ((s) == 4 ? 512: \
    ((s) == 5 ? 1024: \
    ((s) == 6 ? 2048:4096)))))))

const uint_t c_uMaxAllocationSize = PAGE_SIZE - sizeof(uint_t);

EXTERN_C void *malloc(size_t size)
{
    assert(size <= c_uMaxAllocationSize);

    void *pv = (void *)kmalloc(SIZE_TO_INDEX(size + sizeof(uint_t)));

    KMEM_INSERT_INTO_HASH

    return pv;
}

EXTERN_C void free(void *pv)
{
    KMEM_DETACH_FROM_HASH

    kfree((uint_t *)pv);
}


#endif // __ELASTOS_KMALLOC_H__

